CMU 15-112 Spring 2019: Fundamentals of Programming and Computer Science
Homework 10 (Due Sunday 16-Jun, at 10pm)



  1. friendsOfFriends(d) [30 pts]
    This function is not recursive. Background: we can create a dictionary mapping people to sets of their friends. For example, we might say:
    d = { }
    d["spongebob"] = set(["sandy", "patrick", "mr.krabs", "squidward"])
    d["mr.krabs"] = set(["pearl", "spongebob", "squidward"])
    d["pearl"] = set(["mr.krabs"])
    d["sandy"] = set(["spongebob", "patrick"])
    d["patrick"] = set(["spongebob", "sandy"])
    d["squidward"] = set()
    
    With this in mind, write the function friendsOfFriends(d) that takes such a dictionary mapping people to sets of friends and returns a new dictionary mapping all the same people to sets of their friends of friends. For example, since Spongebob is a friend of Patrick, and Squidward is a friend of Spongebob, Squidward is a friend-of-friend of Patrick. This set should exclude any direct friends, so Sandy does not count as a friend-of-friend of Patrick (since she is simply a friend of Patrick) despite also being a friend of Spongebob's.

    Thus, in this example, friendsOfFriends should return:
    {
     'spongebob': {'pearl'}, 
     'mr.krabs': {'patrick', 'sandy'}, 
     'pearl': {'spongebob', 'squidward'}, 
     'sandy': {'mr.krabs', 'squidward'}, 
     'patrick': {'mr.krabs', 'squidward'}, 
     'squidward': set(), 
    }
    
    Note 1: your function should not modify the initial provided dictionary!

    Note 2: you may assume that everyone listed in any of the friend sets also is included as a key in the dictionary.

    Note 3: you may assume that a person will never be included in their own friend set. You should also not include people in their own friends-of-friends sets!

    Note 4: you may not assume that if Person1 lists Person2 as a friend, Person2 will list Person1 as a friend! Sometimes friendships are only one-way. =(

  2. solveABC(constraints, aLocation) [35 pts]
    This problem is inspired by the "ABC Path" problems at BrainBashers.com. For more (optional) info, check this out. In what we will call an "ABC Puzzle", you are given a 5x5 board like this:



    It is an empty board except that it contains a single "A" in an arbitrary cell. Also, the letters from "B" to "Y" are arranged around the outside of the board in an arbitrary order, along with arrows that constrain those letters to a certain row, column, or diagonal. For example, in the image, we see the "H" and "T" are constrained to column 0, "L" and "I" are constrained to row 0, and "C" and "G" are constrained to the column running from (0,0) to (4,4). The goal of this puzzle is to place every letter from "B" to "Y" on the board such that: (1) each letter from "B" to "Y" is placed in the row, column, or diagonal in which it is constrained; and (2) each letter from "B" to "Y" is placed adjacent (including diagonally) to the previous letter (so "B" is adjacent to "A", and "C" is adjacent to "B", and so on).

    A solution to the puzzle shown above is:



    Be sure you understand why this solves the puzzle! If you are unsure, go to the link at BrainBashers.com and read more about this kind of puzzle, including this help page, and maybe try to solve a few more of them (the puzzles include a button you can press to get the solutions!).

    Now, for us to represent one of these puzzles in Python, we have to represent the constraints. We'll do that using a dictionary. The dictionary will have three keys: "rows", "cols", and "diags". "rows" and "cols" will each map to another dictionary which maps indexes of rows/cols to lists of the letters constrained to that row/col. "diags" will map to another dictionary that has two keys, "left" and "right", which map to the letters constrained to the left-down and right-down diagonals. Thus, in the given example, the constraints are:

    constraints = { "rows" : { 0 : ["I", "L"], 1 : ["M", "F"], 2 : ["Y", "N"], 3 : ["D", "U"], 4 : ["Q", "R"] }, "cols" : { 0 : ["H", "T"], 1 : ["J", "W"], 2 : ["X", "K"], 3 : ["B", "E"], 4 : ["O", "P"] }, "diags" : { "left" : ["C", "G"], "right" : ["V", "S"] } }

    We also need to specify the position of the "A", which we will do as a (row,col) tuple, as such:
    aLocation = (0,4)

    With this in mind, write the function solveABC(constraints, aLocation), that takes constraints and the location of the "A", which together define an ABC Puzzle, and returns a completed board which solves the puzzle, or None if no such board exists. Here is a test function that is based on the puzzle used in the example above (notice how the constraints and aLocation match the unsolved puzzle, and the resulting board matches the solved puzzle):

    def testSolveABC(): print('Testing solveABC()...', end='') constraints = { "rows" : { 0 : ["I", "L"], 1 : ["M", "F"], 2 : ["Y", "N"], 3 : ["D", "U"], 4 : ["Q", "R"] }, "cols" : { 0 : ["H", "T"], 1 : ["J", "W"], 2 : ["X", "K"], 3 : ["B", "E"], 4 : ["O", "P"] }, "diags" : { "left" : ["C", "G"], "right" : ["V", "S"] } } aLocation = (0,4) board = solveABC(constraints, aLocation) solution = [ ['I', 'J', 'K', 'L', 'A'], ['H', 'G', 'F', 'B', 'M'], ['T', 'Y', 'C', 'E', 'N'], ['U', 'S', 'X', 'D', 'O'], ['V', 'W', 'R', 'Q', 'P'] ] assert(board == solution) print('Passed!')

    Notes/Hints:
    • To receive any credit for this problem, you must solve it recursively, even if you could dream up a non-recursive solution!
    • This is a backtracking problem. Study the backtracking template and backtracking examples; they will help.
    • You will want to make judicious use of a helper function or optional parameters.


  3. dotsGalore [35 pts]
    Write an animation that runs this very oddly specific game:
    • Every 2 seconds, a dot appears on the canvas in a random position with a random direction. Since it is any direction (not just up, down, left, right), you'll have to keep track of the angle with which each dot moves relative to the x-axis. On every timerFired event, the ball should move in its specified direction. Each dot has its own position and direction. Each ball's speed is left up to you (i.e. they can each have the same speed or different).
    • Each dot has a random radius between 5-50 and a random color (at least 4 colors) from an assortment of any colors you choose.
    • If the dot runs into the wall, it wraps around and re-appears on the other side. The dot will continue to move in the same direction that it was before.
    • If two dots collide, they bounce off of each other. Each dot bounces back in the opposite direction.
    • If you click inside a dot, it is removed from the canvas, and the score is updated by 1.
    • If the user clicks the spacebar, the most recent dot that was removed appears again on the canvas at its previous location and previous direction. Hint: you'll want to keep track of the removed dots.
    • If the user presses "p", the entire game is paused. The dots stop moving, no dots are added, and the user cannot click. If the user presses "p" again, the game is unpaused.
    • If the user presses "r", the game restarts.
    • Every 10 seconds, all of the dots grow by 5 pixels.
    • If there are no dots on the screen and the score is at least 5, new dots should stop spawning and only "Game Over" should be drawn in the center of the screen.
    • The score should be displayed somewhere on the screen.

    Note: Sometimes, dots will spawn on top of other dots and they will vibrate back and forth. This is okay. You do not need to handle this case.